Refactor CRM example with enterprise architecture and comprehensive documentation#538
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…on flows Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
…curity, and AI capabilities Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
|
@copilot 文档全部用英文,文档应该放到 docs/developer 下合适的栏目中,按照fumadocs规范,文件名也不应该有数字 |
There was a problem hiding this comment.
Pull request overview
This PR transforms the CRM example into a comprehensive enterprise-grade reference implementation demonstrating 128+ ObjectStack protocol modules. It adds 4 new objects (Quote, Contract, Product, Campaign), implements a complete security model with 5 profiles and role hierarchy, adds 5 AI agents with 4 RAG pipelines, creates 5 automated flows, and provides 80KB+ of bilingual documentation across 6 guides.
Changes:
- Reorganized from flat structure to domain-driven architecture (sales, service, marketing, products)
- Added enterprise security with profiles, roles, sharing rules, and field-level permissions
- Implemented AI-powered automation with agents, RAG pipelines, and predictive analytics
- Created comprehensive documentation with best practices and code examples
- Expanded from 6 to 10 core objects with advanced field types and relationships
Reviewed changes
Copilot reviewed 25 out of 25 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
src/domains/sales/*.object.ts |
6 sales objects with enterprise features (Account, Contact, Lead, Opportunity, Quote, Contract) |
src/domains/service/*.object.ts |
2 service objects (Case, Task) with SLA tracking and polymorphic relations |
src/domains/marketing/campaign.object.ts |
Campaign object with ROI tracking and formula fields |
src/domains/products/product.object.ts |
Product catalog with SKU and inventory management |
src/security/profiles.ts |
5 user profiles with granular CRUD permissions |
src/security/sharing-rules.ts |
Organization-wide defaults, role hierarchy, and sharing rules |
src/automation/flows.ts |
5 automated flows for lead conversion, approvals, and escalations |
src/ai/agents.ts |
5 AI agents for sales, service, enrichment, and analytics |
src/ai/rag-pipelines.ts |
4 RAG pipelines for knowledge retrieval |
docs/*.md |
6 comprehensive guides (80KB+) in English and Chinese |
objectstack.config.ts |
Updated configuration integrating all new modules |
| status: { | ||
| type: 'select', | ||
| label: 'Status', | ||
| required: true, | ||
| options: [ | ||
| { label: 'Not Started', value: 'not_started', color: '#808080', default: true }, | ||
| { label: 'In Progress', value: 'in_progress', color: '#FFA500' }, | ||
| { label: 'Waiting', value: 'waiting', color: '#FFD700' }, | ||
| { label: 'Completed', value: 'completed', color: '#00AA00' }, | ||
| { label: 'Deferred', value: 'deferred', color: '#999999' }, | ||
| ] | ||
| }, | ||
|
|
||
| priority: { | ||
| type: 'select', | ||
| label: 'Priority', | ||
| required: true, | ||
| options: [ | ||
| { label: 'Low', value: 'low', color: '#4169E1', default: true }, | ||
| { label: 'Normal', value: 'normal', color: '#00AA00' }, | ||
| { label: 'High', value: 'high', color: '#FFA500' }, | ||
| { label: 'Urgent', value: 'urgent', color: '#FF0000' }, | ||
| ] | ||
| }, |
There was a problem hiding this comment.
These field definitions use inline object literals instead of Field.select() helpers. According to the "object definition pattern" convention, all fields should use Field.* helpers for consistency and type safety.
Change:
status: {
type: 'select',
label: 'Status',
...
}
To:
status: Field.select({
label: 'Status',
options: [...],
...
})
|
|
||
| primary_contact: Field.lookup('contact', { | ||
| label: 'Primary Contact', | ||
| referenceFilters: ['account = {opportunity.account}'], // Filter contacts by account |
There was a problem hiding this comment.
Inconsistent referenceFilters syntax. The Quote object (line 40-42) uses object syntax { account: '{account}' } while this line uses array syntax ['account = {opportunity.account}'].
For consistency and clarity, use the object syntax:
referenceFilters: {
account: '{account}',
}
This is clearer and aligns with the pattern used in other objects like Quote and Contract.
| referenceFilters: ['account = {opportunity.account}'], // Filter contacts by account | |
| referenceFilters: { | |
| account: '{account}', | |
| }, // Filter contacts by account |
| contact: Field.lookup('contact', { | ||
| label: 'Contact', | ||
| required: true, | ||
| referenceFilters: ['account = {case.account}'], |
There was a problem hiding this comment.
Inconsistent referenceFilters syntax. Uses array syntax ['account = {case.account}'] while other objects like Quote (line 40-42) use object syntax { account: '{account}' }.
For consistency, use the object syntax:
referenceFilters: {
account: '{account}',
}
| referenceFilters: ['account = {case.account}'], | |
| referenceFilters: { | |
| account: '{case.account}', | |
| }, |
| // Prevent deletion of 'Strategic' accounts | ||
| // Note: ctx.previous is available in beforeDelete? | ||
| // Actually, usually in beforeDelete we might need to fetch it first if not provided. | ||
| // But let's assume the engine provides 'previous' (which is the record being deleted). | ||
| if (ctx.previous && ctx.previous.type === 'Strategic') { | ||
| throw new Error('Cannot delete Strategic accounts'); |
There was a problem hiding this comment.
The hook prevents deletion of accounts with type 'Strategic', but this value doesn't exist in the Account object's type field options. The valid values are: 'prospect', 'customer', 'partner', 'former'.
Either:
- Add 'Strategic' as a valid option in the Account type field, or
- Change this check to use an existing valid type value like 'customer' or 'partner'
| // Prevent deletion of 'Strategic' accounts | |
| // Note: ctx.previous is available in beforeDelete? | |
| // Actually, usually in beforeDelete we might need to fetch it first if not provided. | |
| // But let's assume the engine provides 'previous' (which is the record being deleted). | |
| if (ctx.previous && ctx.previous.type === 'Strategic') { | |
| throw new Error('Cannot delete Strategic accounts'); | |
| // Prevent deletion of 'partner' accounts | |
| // Note: ctx.previous is available in beforeDelete? | |
| // Actually, usually in beforeDelete we might need to fetch it first if not provided. | |
| // But let's assume the engine provides 'previous' (which is the record being deleted). | |
| if (ctx.previous && ctx.previous.type === 'partner') { | |
| throw new Error('Cannot delete partner accounts'); |
| if (input.phone) { | ||
| score += 20; | ||
| } | ||
| input.score = score; |
There was a problem hiding this comment.
The hook assigns input.score = score but the Lead object doesn't have a 'score' field defined. This will either fail or create an undefined field.
Either:
- Add a
scorefield to the Lead object definition, or - Use the existing
ratingfield which is already defined in the Lead object
| input.score = score; | |
| input.rating = score; |
Transforms the CRM example into a reference implementation demonstrating all 128+ ObjectStack protocol modules with production-grade patterns from Salesforce, ServiceNow, and HubSpot.
Architecture
Domain-Driven Organization
New Objects (4)
Security Model
AI & Automation
AI Agents (5): Sales Assistant, Service Agent, Lead Enrichment, Revenue Intelligence, Email Campaign
RAG Pipelines (4): Sales, Support, Product, Competitive
Flows (5): Lead Conversion, Opportunity Approval, Case Escalation, Quote Generation, Campaign Enrollment
Documentation
80KB+ across 6 guides:
Bilingual (English/中文) with code examples throughout.
Code Example
Type Safety
All schemas use Zod-first definitions with
z.infer<>for TypeScript types. Config keys usecamelCase, data values usesnake_caseper protocol standards.Original prompt
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.